/*

    tools23d - tools for converting images to 3D formats.
    Copyright (C) 2014  Dave Gorst

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/


/**
 * @file   cli.c
 * @brief  Commandline functions common to both btime23d and photo23d.
 *
 */

/*
 * WARNING : Testing sequences consisting of a percentage sign and then hexadecimal digits will be converted to the ASCII equivalent character when debugging in MSVC 2010!
 *
 * Use "%25" in place of "%" to get around this.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "tools23d.h"

#ifdef BUILD_BTIME
	#include "btime23d.h"
	#include "cli-btime.h"
#else
	#include "photo23d.h"
	#include "cli-photo.h"
#endif

#include "cli-common.h"
#include "cli.h"
#include "readml.h"
#include "util.h"
#include "list.h"
#include "system.h"

/**
Common commandline argument handling.

@param	argc		Number of commandline arguments.
@param	argv		Pointer to a string array containing arguments.
@param	cli_params	Pointer to a structure of input options.
@return	Returns ::t3d_return indicating whether processing was successful.
*/

t3d_return T3D_ProcessCommandline (int argc, char * argv [], params * cli_params)
{
	t3d_return retcode = t3d_success;
	BOOL success = TRUE;

	T3D_ClearGeneralParams (cli_params);
	T3D_ClearAppParams (cli_params);

	retcode = T3D_HandleOptions(argc, argv, cli_params);

	if ((cli_params->loglevel > Quiet) || (retcode == t3d_displayhelp))
		T3D_PrintBanner();

	if (T3D_CheckForError())
		T3D_OutputError("%s\n\n", T3D_ReadLastError());

	if ((retcode == t3d_displayhelp) || (cli_params->loglevel > Quiet))
	{
		T3D_PrintHeader ();
		T3D_ListOptions ();
		T3D_PrintFooter ();
	}

	return retcode;
}

/**
Process commandline arguments.

@param	argc		Number of commandline arguments.
@param	argv		Pointer to a string array containing arguments.
@param	cli_params	Pointer to a structure of input options.
@return	Returns ::t3d_return indicating whether processing was successful.
*/

t3d_return T3D_HandleOptions (int argc, char * argv[], params * cli_params)
{
	char currentSwitch;
	char * current_arg;

	int arg = 1;
	unsigned int fixed_arg = 0;

	char ** fixed_list = NULL;
	t3d_return retcode = t3d_success;

	while ((arg < argc) && (T3D_CheckForError() != TRUE) && (retcode == t3d_success))
	{
		current_arg = argv [arg];
		if ((current_arg[0] == '-') && (!T3D_IsNumeric (current_arg)))
		{
			if (current_arg[1] == '-')
			{
				/* Long option */
				currentSwitch = T3D_FindShortSwitch (current_arg + 2);
			}
			else
				currentSwitch = current_arg[1];

			arg++;

			if ((currentSwitch != SWITCH_NOT_FOUND) && ((currentSwitch >= 'a') && (currentSwitch <= 'z')))
				retcode = common_options_table [currentSwitch - 'a'].func (currentSwitch, cli_params, &arg, argc, argv);
			else
			{
				T3D_SetLastError ("Unknown option \"%.10s\".", current_arg);
				retcode = t3d_bad_parameter;
			}
		}
		else
		{
			fixed_list = T3D_AddToList (&fixed_arg, fixed_list, current_arg);
			arg++;
		}
	}

	if ((T3D_CheckForError () != TRUE) && (retcode == t3d_success))
	{
		if (T3D_HandleFixedArgs (cli_params, fixed_arg, fixed_list))
		{
			T3D_SetGeneralDefaults (cli_params);
			T3D_SetAppDefaults (cli_params);

			retcode = t3d_success;
		}
		else
			retcode = t3d_bad_parameter;
	}

	T3D_DestroyList(fixed_arg, fixed_list);

	return retcode;
}

/**
Scan the list of long options and find the short switch equivalent.

@param	input_long		String containing the entered long switch.
@return	Returns the found short switch or ::SWITCH_NOT_FOUND.
*/

char T3D_FindShortSwitch (char * input_long)
{
	int current_letter;
	char short_switch = SWITCH_NOT_FOUND;

	for (current_letter = 'a'; ((current_letter <= 'z') && (short_switch == SWITCH_NOT_FOUND)); current_letter++)
	{
		if (common_options_table [current_letter - 'a'].long_option != NULL)
		{
			if (!strcmp (common_options_table [current_letter - 'a'].long_option, input_long))
				short_switch = current_letter;
		}
		else
		{
			if (app_options_table [current_letter - 'a'].long_option != NULL)
				if (!strcmp (app_options_table [current_letter - 'a'].long_option, input_long))
					short_switch = current_letter;
		}
	}

	return short_switch;
}


/**
List all the general and app-specific options available.

*/

void T3D_ListOptions (void)
{
	char current_option;

	for (current_option = 'a'; current_option <= 'z'; current_option++)
	{
		if (common_options_table [current_option - 'a'].long_option != NULL)
			T3D_ShowOption (current_option, common_options_table [current_option - 'a'].long_option, common_options_table [current_option - 'a'].help_text);
	}
	for (current_option = 'a'; current_option <= 'z'; current_option++)
	{
		if (app_options_table [current_option - 'a'].long_option != NULL)
			T3D_ShowOption (current_option, app_options_table [current_option - 'a'].long_option, app_options_table [current_option - 'a'].help_text);
	}
}


/**
Scan the list of long options and find the short switch equivalent.

@param	short_option		Character containing the short switch.
@param	long_option			String containing the long switch.
@param	help_text			String containing description of switch.

*/

void T3D_ShowOption (char short_option, char * long_option, char * help_text)
{
	int xpos;

	readml_return retcode;
	BOOL first_line = TRUE;
	char line_buffer [256];

	T3D_OutputMessage ("  -%c [--%s]", short_option, long_option);

	xpos = 9 + strlen (long_option);

	do
	{
		if (first_line)
		{
			retcode = T3D_GetFirstLine (&line_buffer [0], help_text);
			first_line = FALSE;
		}
		else
			retcode = T3D_GetNextLine (&line_buffer [0]);

		if (retcode != readml_error)
		{
			while (xpos++ < 24)
				T3D_OutputMessage (" ");

			T3D_OutputMessage (line_buffer);
			T3D_OutputMessage ("\n");
			xpos = 0;
		}
	}
	while (retcode == readml_success);
}
